package com.chenjun.designpattern.behavior.visitor;

import java.util.HashSet;
import java.util.Set;

/**
 * 2017年4月4日10:37:32
 * 访问者模式结构：<br/>
访问者角色(Visitor): 为该对象结构中具体元素角色声明一个访问操作接口. <br/>
具体访问者角色(Concrete Visitor): 实现每个由访问者角色(Visitor)声明的操作.<br/>
元素角色(Element): 定义一个Accept操作，它以一个访问者为参数.<br/>
具体元素角色(Concrete Element): 实现由元素角色提供的Accept操作.<br/>
对象结构角色(Object Structure): 这是使用访问者模式必备的角色. 它要具备以下特征: 能枚举它的元素; <br/>
可以提供一个高层的接口以允许该访问者访问它的元素; 可以是一个复合(组合模式)或是一个集合, 如一个列表或一个无序集合.<br/>

观察规律和个人总结： 访问者模式的精髓就在于每个具体元素都有了 fun(Visitor visitor) 形式的方法 ，然后把自身的this引用当做visitor.visit(参数) 的“参数”传到了具体访问者里面

 * @author Administrator
 *
 */
public class 访问者模式2
{
	public static void main(String[] args)
	{
		final StructObject object = new StructObject();
		
		object.add(new ConcreteElement1());
		object.add(new ConcreteElement2());
		
		/**
		 * 因为是HashSet，所以最好输出可能是无序的
		 */
		object.allElementAccept(new ConcreteVisitor());
	}
}

/**
 * 抽象访问者对象
 * 
 * @author Administrator
 *
 */
interface Visitor
{
	public void visit(ConcreteElement1 element1);

	public void visit(ConcreteElement2 element2);
}

/**
 * 具体观察者对象
 * 
 * @author Administrator
 */
class ConcreteVisitor implements Visitor
{
	@Override
	public void visit(ConcreteElement1 element1)
	{
		System.out.println("element1:"+element1.getClass().getSimpleName());
	}

	@Override
	public void visit(ConcreteElement2 element2)
	{
		System.out.println("element2:"+element2.getClass().getSimpleName());
	}
}

abstract class Element
{
	/**
	 * 定义一个抽象方法接受访问者对象
	 * 
	 * @param visitor
	 */
	public abstract void accept(Visitor visitor);
}

class ConcreteElement1 extends Element
{
	@Override
	public void accept(Visitor visitor)
	{
		visitor.visit(this);
	}
}

class ConcreteElement2 extends Element
{
	@Override
	public void accept(Visitor visitor)
	{
		visitor.visit(this);
	}
}

/**
 * 结构类对象.,内部包含了具体的元素对象（被访问者）
 */
class StructObject
{
	Set<Element> sets = new HashSet<Element>();

	public void add(Element e)
	{
		sets.add(e);
	}

	public void remove(Element e)
	{
		sets.remove(e);
	}

	/**
	 * 遍历集合，让所有元素接受被访问者
	 * @param visitor
	 */
	public void allElementAccept(final Visitor visitor)
	{
		for (final Element e : sets)
		{
			e.accept(visitor);
		}
	}
}
